package com.gitee.wsl.mathematics.vector.vec4

import com.gitee.wsl.ext.array.FloatArray
import com.gitee.wsl.io.dataproxy.DataGet
import com.gitee.wsl.io.dataproxy.asProxy
import com.gitee.wsl.mathematics.vector.vec2.Vec2f
import com.gitee.wsl.mathematics.vector.vec3.Vec3f


/**
 * A class representing a four-dimensional vector.
 */
open class Vec4f(override val proxy: DataGet<Float>): Vector4F<Vec4f> {
    constructor(x: Float=0.0f,
                y: Float=0.0f,
                z: Float=0.0f,
                w: Float=0.0f):this(FloatArray(x,y,z,w).asProxy())
    constructor(a: Number) : this(a.toDouble(), a.toDouble(), a.toDouble(), a.toDouble())
    constructor(x: Number, y: Number, z: Number, w: Number) : this(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())
    constructor(base: Vector4<*,*>) : this(base.x, base.y, base.z, base.w)

    override val self
        get() = this

    override fun createVec2(a: Float, b: Float):Vec2f = Vec2f(a,b)

    override fun createVec3(a: Float, b: Float, c: Float):Vec3f = Vec3f(a,b,c)

    override fun create(x: Float, y: Float, z: Float, w: Float): Vec4f = Vec4f(x, y, z, w)

    /**Reflects the vector from [normal].*/
    /*open infix fun reflectFrom(normal: Vec4f): Vec4f {
        val norm = normal.normalized
        val factor = -2.0 * this dot norm
        return factor * norm + this
    }*/
    /**Reflects the vector from [normal].*/
    /*open infix fun reflectFrom(normal: Vec3f) = reflectFrom(normal.vec4)
    *//**Reflects the vector from [normal].*//*
    open infix fun reflectFrom(normal: Vec2f) = reflectFrom(normal.vec4)*/

    override fun toString(): String {
        val xInt = x.toInt(); val yInt = y.toInt(); val zInt = z.toInt(); val wInt = w.toInt()
        val xs = if (x == xInt.toFloat()) xInt.toString() else x.toString()
        val ys = if (y == yInt.toFloat()) yInt.toString() else y.toString()
        val zs = if (z == zInt.toFloat()) zInt.toString() else z.toString()
        val ws = if (w == wInt.toFloat()) wInt.toString() else w.toString()

        return "[$xs, $ys, $zs, $ws]"
    }
    override fun equals(other: Any?) = other is Vec4f && x == other.x && y == other.y && z == other.z && w == other.w
    override fun hashCode() = 31 * (31 * (31 * x.hashCode() + y.hashCode()) + z.hashCode()) + w.hashCode()

    companion object {
        val ONE get() = Vec4f(1.0, 1.0, 1.0, 1.0)
        val ZERO get() = Vec4f(0.0, 0.0, 0.0, 0.0)
        val right get() = Vec4f(1.0, 0.0, 0.0, 0.0)
        val left get() = Vec4f(-1.0, 0.0, 0.0, 0.0)
        val up get() = Vec4f(0.0, 1.0, 0.0, 0.0)
        val down get() = Vec4f(0.0, -1.0, 0.0, 0.0)
        val forward get() = Vec4f(0.0, 0.0, 1.0, 0.0)
        val backward get() = Vec4f(0.0, 0.0, -1.0, 0.0)
        val negativeInfinity get() = Vec4f(Double.NEGATIVE_INFINITY)
        val positiveInfinity get() = Vec4f(Double.POSITIVE_INFINITY)

        val UNIT_X = Vec4f(1.0, 0.0, 0.0, 0.0)
        val UNIT_Y = Vec4f(0.0, 1.0, 0.0, 0.0)
        val UNIT_Z = Vec4f(0.0, 0.0, 1.0, 0.0)
        val UNIT_W = Vec4f(0.0, 0.0, 0.0, 1.0)

        val INFINITY = Vec4f(
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY
        )

    }
}

inline fun Vec4f.toMutableVec4() = MutableVec4f(x,y, z, w)

/*

*/
/**
 * A class representing a four-dimensional vector.
 *//*

open class Vec4f2(x: Float, y: Float, z: Float, w: Float, override val values: FloatArray = FloatArray(x,y,z,w)):
    Vector4f<Vec4f>{
    constructor() : this(0.0f, 0.0f, 0.0f, 0.0f)
    constructor(a: Number) : this(a.toDouble(), a.toDouble(), a.toDouble(), a.toDouble())
    constructor(x: Number, y: Number, z: Number, w: Number) : this(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat())

    */
/*open val x
        get() = this[0]

    open val y
        get() = this[1]

    open val z
        get() = this[2]

    open val w
        get() = this[3]

    override val length
        get() = sqrt(sqrLength)

    override val sqrLength get() = x * x + y * y + z * z + w * w

    override val normalized get() = this / length
    override val abs get() = Vec4f(abs(x), abs(y), abs(z), abs(w))
    override val sign get() = Vec4f(sign(x), sign(y), sign(z), sign(w))
    override val ceil get() = Vec4f(ceil(x), ceil(y), ceil(z), ceil(w))
    override val floor get() = Vec4f(floor(x), floor(y), floor(z), floor(w))
    override val round get() = Vec4f(round(x), round(y), round(z), round(w))*//*

    override val vec2 get() = Vec2f(x, y)
    override val vec3 get() = Vec3f(x, y, z)
    override val vec4 get() = this

    companion object {
        val one get() = Vec4f(1.0, 1.0, 1.0, 1.0)
        val zero get() = Vec4f(0.0, 0.0, 0.0, 0.0)
        val right get() = Vec4f(1.0, 0.0, 0.0, 0.0)
        val left get() = Vec4f(-1.0, 0.0, 0.0, 0.0)
        val up get() = Vec4f(0.0, 1.0, 0.0, 0.0)
        val down get() = Vec4f(0.0, -1.0, 0.0, 0.0)
        val forward get() = Vec4f(0.0, 0.0, 1.0, 0.0)
        val backward get() = Vec4f(0.0, 0.0, -1.0, 0.0)
        val negativeInfinity get() = Vec4f(Double.NEGATIVE_INFINITY)
        val positiveInfinity get() = Vec4f(Double.POSITIVE_INFINITY)
    }

    override operator fun plus(other: Vec4f) = Vec4f(x + other.x, y + other.y, z + other.z, w + other.w)
    open operator fun plus(other: Vec3f) = Vec4f(x + other.x, y + other.y, z + other.z, w)
    open operator fun plus(other: Vec2f) = Vec4f(x + other.x, y + other.y, z, w)

    override operator fun minus(other: Vec4f) = Vec4f(x - other.x, y - other.y, z - other.z, w - other.w)
    open operator fun minus(other: Vec3f) = Vec4f(x - other.x, y - other.y, z - other.z, w)
    open operator fun minus(other: Vec2f) = Vec4f(x - other.x, y - other.y, z, w)

    override operator fun times(a: Number) = Vec4f(x * a.toDouble(), y * a.toDouble(), z * a.toDouble(), w * a.toDouble())
    override operator fun times(other: Vec4f) = Vec4f(x * other.x, y * other.y, z * other.z, w * other.w)
    open operator fun times(other: Vec3f) = Vec4f(x * other.x, y * other.y, z * other.z, 0.0)
    open operator fun times(other: Vec2f) = Vec4f(x * other.x, y * other.y, 0.0, 0.0)

    override operator fun div(a: Number) = Vec4f(x / a.toDouble(), y / a.toDouble(), z / a.toDouble(), w / a.toDouble())
    override operator fun div(other: Vec4f) = Vec4f(x / other.x, y / other.y, z / other.z, w / other.w)
    open operator fun div(other: Vec3f) = Vec4f(x / other.x, y / other.y, z / other.z, Double.POSITIVE_INFINITY)
    open operator fun div(other: Vec2f) = Vec4f(x / other.x, y / other.y, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)
    override fun divBy(a: Number): Vec4f = Vec4f(a.toDouble() / x, a.toDouble() / y, a.toDouble() / z, a.toDouble() / w)

    override operator fun rem(a: Number) = Vec4f(x % a.toDouble(), y % a.toDouble(), z % a.toDouble(), w % a.toDouble())
    override operator fun rem(other: Vec4f) = Vec4f(x % other.x, y % other.y, z % other.z, w % other.w)
    open operator fun rem(other: Vec3f) = Vec4f(x % other.x, y % other.y, z % other.z, Double.NaN)
    open operator fun rem(other: Vec2f) = Vec4f(x % other.x, y % other.y, Double.NaN, Double.NaN)
    override fun remBy(a: Number): Vec4f = Vec4f(a.toDouble() % x, a.toDouble() % y, a.toDouble() % z, a.toDouble() % w)

    override operator fun unaryMinus() = Vec4f(-x, -y, -z, -w)

    */
/**The distance from this vector to [other].*//*

    override infix fun distanceTo(other: Vec4f) = (other - this).length
    */
/**The distance from this vector to [other].*//*

    infix fun distanceTo(other: Vec3f) = (other - this).length
    */
/**The distance from this vector to [other].*//*

    infix fun distanceTo(other: Vec2f) = (other - this).length

    */
/**The normal direction from this vector to [other].*//*

    infix fun directionTo(other: Vec2f) = (other - this).normalized
    */
/**The normal direction from this vector to [other].*//*

    infix fun directionTo(other: Vec3f) = (other - this).normalized
    */
/**The normal direction from this vector to [other].*//*

    override infix fun directionTo(other: Vec4f) = (other - this).normalized

    override infix fun dot(other: Vec4f) = x * other.x + y * other.y + z * other.z + w * other.w
     infix fun dot(other: Vec3f) = x * other.x + y * other.y + z * other.z
     infix fun dot(other: Vec2f) = x * other.x + y * other.y

    */
/**The projection of this vector onto [other].*//*

     infix fun projectOn(other: Vec2f) = other * dot(other) / other.sqrLength
    */
/**The projection of this vector onto [other].*//*

     infix fun projectOn(other: Vec3f) = other * dot(other) / other.sqrLength
    */
/**The projection of this vector onto [other].*//*

    override infix fun projectOn(other: Vec4f) = other * dot(other) / other.sqrLength

    */
/**Reflects the vector from [normal].*//*

    override infix fun reflectFrom(normal: Vec4f): Vec4f {
        val norm = normal.normalized
        val factor = -2.0 * this dot norm
        return factor * norm + this
    }
    */
/**Reflects the vector from [normal].*//*

    infix fun reflectFrom(normal: Vec3f) = reflectFrom(normal.vec4)
    */
/**Reflects the vector from [normal].*//*

    infix fun reflectFrom(normal: Vec2f) = reflectFrom(normal.vec4)


    override fun toString(): String {
        val xInt = x.toInt(); val yInt = y.toInt(); val zInt = z.toInt(); val wInt = w.toInt()
        val xs = if (x == xInt.toFloat()) xInt.toString() else x.toString()
        val ys = if (y == yInt.toFloat()) yInt.toString() else y.toString()
        val zs = if (z == zInt.toFloat()) zInt.toString() else z.toString()
        val ws = if (w == wInt.toFloat()) wInt.toString() else w.toString()

        return "[$xs, $ys, $zs, $ws]"
    }
    override fun equals(other: Any?) = other is Vec4f && x == other.x && y == other.y && z == other.z && w == other.w
    override fun hashCode() = 31 * (31 * (31 * x.hashCode() + y.hashCode()) + z.hashCode()) + w.hashCode()
}*/
